
# -*- coding: utf-8 -*-
'''
Created on 18/nov/2010

@author: alessio irene
'''

from icalendar import Calendar, Event, Journal
import string
from bsddb import db
import os
import StringIO
##@author Alessio Di Pietro
#@author Irene Scionti
#@brief Parser for pim data stored in evolution files. 
class pimParser(object):
    '''
    Parse pim information from ics and berkley db file format for single entry versioning
    '''
    
    def __init__(self,settings):
        '''
        Constructor
        @param
        '''
        #getting the path of the workingCopy where the directories with the split data will be stored from the settings' file. 
        self.__splitPath=settings.svnWorkingCopy;
        #getting the directories calendar, contacts and memos for the pim entries' storage .
        self.__pim_paths=[settings.contacts_diffname,settings.calendar_diffname,settings.memos_diffname];
        #getting the the paths of the evolution file as source of pim data.
        self.__diff_sources=[settings.contactspath,settings.icspath,settings.memospath]
        
        #setting the tag that aren't shown in the result of the search of an event or a memo in versionsynwebapp
        self.__ics_clean_tags={}
        self.__ics_clean_tags['BEGIN']=True
        self.__ics_clean_tags['DTSTAMP']=True
        self.__ics_clean_tags['UID']=True
        self.__ics_clean_tags['CREATED']=True
        self.__ics_clean_tags['SEQUENCE']=True
        self.__ics_clean_tags['TRANSP']=True
        self.__ics_clean_tags['LAST-MODIFIED']=True
        self.__ics_clean_tags['END']=True
        self.__ics_clean_tags['CLASS']=True
        #setting the tag that aren't shown in the result of the search of a contact in versionsynwebapp
        self.__cntc_except_tags={}
        self.__cntc_except_tags['BEGIN']=True
        self.__cntc_except_tags['VERSION']=True
        self.__cntc_except_tags['UID']=True
        self.__cntc_except_tags['ADR']=True
        self.__cntc_except_tags['N']=True
        self.__cntc_except_tags['EVOLUTION-SPOUSE']=True
        self.__cntc_except_tags['X-MOZILLA-HTML']=True
        self.__cntc_except_tags['X-EVOLUTION-FILE-AS']=True
        self.__cntc_except_tags['X-EVOLUTION-ASSISTANT']=True
        self.__cntc_except_tags['X-EVOLUTION-MANAGER']=True
        self.__cntc_except_tags['X-EVOLUTION-SPOUSE']=True
        self.__cntc_except_tags['END']=True
        
    '''
    Setter and Getter methods
    '''
    
    def setSvnWcopy(self,svn_wcopy):
            self.svn_wcopy=svn_wcopy
    def setSplitPath(self,splitPath):
        self.__splitPath=splitPath;
    
    #icsSplit() split calendar.ics of evolution in entries that are stored separately in directories located in the workingcopy/calendar
    ## @return  event_files a list containing all the split entries stored 
    def icsSplit(self):
        '''
        Splits an ics file into multiple ics files (named with entry UID) 
        that contain the single entry
        '''
        event_files=[];
        #opening the source file of pim data
        cal = Calendar.from_string(open(self.__diff_sources[1],'r').read())
        ev0=None
        #for every event stored in the calendar
        for ev0 in cal.walk('vevent'):
            #create a directory named by the unique identifier of the entry if not exists
            UUID = ev0['UID']
            if not os.path.exists(self.__splitPath+self.__pim_paths[1]+'/'+str(UUID)):
                os.mkdir(self.__splitPath+self.__pim_paths[1]+'/'+str(UUID))
            seq = (self.__splitPath+self.__pim_paths[1],str(UUID),str(UUID));
            nome_file="/".join(seq)
            #in this directory, file named by the unique identifier of the entry is opened for storing the content of the entry:
            
            f=open(nome_file, 'w')
            #split entry added to event_files list 
            event_files.append(unicode(UUID))
            
            if ev0 != None:
                #write into a file the content of the entry
                print >> f, "BEGIN:VEVENT"
                for component in ev0:
                    #encode/decode 'utf-8' for reading words with special character
                    seq2=(str(component),":",(str(ev0[str(component)])).decode('utf-8'))
                    line="".join(seq2)
                    print >> f,line.encode('utf-8')
                print >> f, "END:VEVENT"
            
            f.close()
      
        return event_files
    #contactSplit() split address_book.db of evolution in entries that are stored separately in directories located in the workingcopy/contacts
    ## @return  contact_files a list containing all the split entries stored 
    def contactSplit(self):
        '''
        Splits a berkley db file into multiple bdb files (named with entry UID) 
        that contain the single entry
                
        ''' 
        contact_files=[];
        contactDB=db.DB()
        #opening the address_book.db containing the contacts
        contactDB.open(self.__diff_sources[0], None, db.DB_HASH, db.DB_DIRTY_READ)
        #a cursor for moving between the records of the db.
        cursor=contactDB.cursor()
        #getting all the keys of the records in the db 
        array_key=contactDB.keys()
        rec=cursor.first()
        if len(array_key)>1:
            data=contactDB.get(array_key[1])
            i=0
            #for every record   
            while rec:
                #getting the key of the record to obtein the name of the file where the content of the record will be stored
                buffer_cntc_id=''
                if string.find(array_key[i],'pas-id')!=-1:
                     
                    if string.find(array_key[i],'pas-id')>0 :
                        buffer=array_key[i];
                        buffer_cntc_id=buffer[1:(len(buffer)-2)]
                    else:
                        cntc_id=str(array_key[i]).split('\x00')
                        buffer_cntc_id=str(cntc_id[0]);
                    #if not exixt the path , it is created
                    if not os.path.exists(self.__splitPath+self.__pim_paths[0]+'/'+str(buffer_cntc_id)):
                        os.mkdir(self.__splitPath+self.__pim_paths[0]+'/'+str(buffer_cntc_id))
                    seq = (self.__splitPath+self.__pim_paths[0],str(buffer_cntc_id),str(buffer_cntc_id));
            
                    nome_file="/".join(seq)
                    f=open(nome_file, 'w')
                    #the content of the record is stored 
                    #encode/decode 'utf-8' for reading words with special character
                    data=(contactDB.get(array_key[i])+"\x00\n").decode('utf-8')
                    print >>f, data.encode('utf-8')
                    #record added to event_files list 
            
                    contact_files.append(unicode(buffer_cntc_id))
                    f.close()
                    
                rec=cursor.next()
                #if the cursor is NoneType, go out from the cycle.
                if rec==None :
                   
                    break;
                
                i=i+1
        contactDB.close()
        
        return contact_files
    
    ##@brief memosSplit() split journal.ics of evolution in entries that are stored separately in directories located in the workingcopy/memos
    # @return  memos_files a list containing all the split entries stored 
    def memosSplit(self):
        memos_files=[];
        #opening the source file of pim data
        cal = Calendar.from_string(open(self.__diff_sources[2],'rb').read())
        jou0=None
        #for every memo stored in the journal
        for jou0 in cal.walk('VJOURNAL'):
            if jou0 != None:
                UUID = jou0['UID']
                #create a directory named by the unique identifier of the entry if not exists
                if not os.path.exists(self.__splitPath+self.__pim_paths[2]+'/'+str(UUID)):
                    os.mkdir(self.__splitPath+self.__pim_paths[2]+'/'+str(UUID))
                seq = (self.__splitPath+self.__pim_paths[2], str(UUID),str(UUID));
                
                nome_file="/".join(seq)
                #in this directory, file named by the unique identifier of the entry is opened for storing the content of the entry:
            
                f=open(nome_file, 'w')
                #split entry added to memos_files list 
            
                memos_files.append(unicode(UUID))
                #write into a file the content of the entry
                print >> f, "BEGIN:VJOURNAL"
                for component in jou0:
                    #encode/decode 'utf-8' for reading words with special character
                    seq2 = (str(component),str(jou0[str(component)]))
                    memo_line=":".join(seq2)
                    print >> f, memo_line
                   
                print >> f, "END:VJOURNAL"
                f.close()
        return memos_files
    
    ##@param entry_uid uid of the event entry
    ##@return calendar event dtstamp in iso8601 format
    def calendar_dtstamp_parse(self,entry_uid):
        '''
        parse the dtstamp content field of calendar event in iso8601 format
        '''
        cal = Calendar.from_string(open(self.__splitPath+self.__pim_paths[1]+"/"+entry_uid+"/"+entry_uid,'r').read())
        for ev in cal.walk('vevent'):
            dtstamp=str(ev['DTSTAMP'])
        return dtstamp[:4]+'-'+dtstamp[4:6]+'-'+dtstamp[6:11]+':'+dtstamp[11:13]+':'+dtstamp[13:]
    
    ##@brief parse the memo DTSTAMP in iso8601 format
    #@param entry_uid uid of the memo entry
    # @return dtstamp in iso8601 format
    def memo_dtstamp_parse(self,entry_uid):
        '''
        parse the dtstamp content field of memo in iso8601 format
        '''
        cal = Calendar.from_string(open(self.__splitPath+self.__pim_paths[2]+"/"+entry_uid+"/"+entry_uid,'r').read())
        for ev in cal.walk('VJOURNAL'):
            dtstamp=str(ev['DTSTAMP'])
        return dtstamp[:4]+'-'+dtstamp[4:6]+'-'+dtstamp[6:11]+':'+dtstamp[11:13]+':'+dtstamp[13:]
    
    ##@param entry_uid uid of the contact entry
    # @return contact rev in iso8601 format
    def contact_rev_parse(self,entry_uid):
        '''
        parse the rev content field of contact entry in iso8601 format
        '''
        entry_body=open(self.__splitPath+self.__pim_paths[0]+"/"+entry_uid+"/"+entry_uid,'r').read()
        index_found=string.find(entry_body,"REV:")
        rev=entry_body[index_found+4:index_found+20]+"Z"
        return rev
    ###@brief made the research result showing only some informations stored in the memo or event entry founded.
    #@param body field body of result's record  searched in memos_index or calendar_index of fts_index.db
    #@return cleaned_body body without some tags
    def ics_body_cleaner(self, body):
        '''
        clean the body removing those tags that have meaningless informations for the user.
        those tags are indicated in enum ics_clean_tags
        '''
        cal = Calendar.from_string(body)
        cleaned_body='';
        
        for ev in cal.items():
            present=False;
            
            try:
                self.__ics_clean_tags[str(ev[0])]
            except KeyError:
                present=True;
            if present:
                tag=str(ev[0])
                value=str(ev[1])
                if (tag=='DTSTART') or ( tag=='DTEND'):
                    if tag=='DTSTART':
                        tag='STARTS'
                    if tag=='DTEND':   
                        tag='ENDS'
                    value=value[:4]+'-'+value[4:6]+'-'+value[6:11]+':'+value[11:13]+':'+value[13:]
                cleaned_body+="\n"+tag+' : '+value;
                
        return cleaned_body;
    
    ##@brief makes the research result showing only some informations stored in the contact entry founded.
    #@param body field body of result's record  searched in table contacts_index of fts_index.db
    #@return cleaned_body body with only some tags
    def vcard_body_cleaner(self,body):
        '''
        clean the body leaving those tags that have meaningful informations for the user.
        those tags that aren't indicated in enum cntc_except_tags are removed
        '''
        
        
        cleaned_body='';
        
        body5=body.split("\r\n")
        for i in range (0, len(body5)):
            temp=(body5[i]).split(":")
            if len(temp)>1 :
                seq=[]
                for j in range(1,len(temp)):
                    seq.append(temp[j])
                value=":".join(seq)
            else :
                value=temp[1]
            temp_bis=(temp[0]).split(";")
            
            present=False;
            try:
                self.__cntc_except_tags[(temp_bis[0])]
            except KeyError:
                present=True;
            if (present==True) and (temp[1]!=""):
                tag=temp_bis[0]
                if tag.find('X-') >=0 : 
                        tag=tag[2:]
                if tag=='FN' : 
                        tag='NAME'
                if tag=='EVOLUTION-BLOG-URL' :
                        tag='BLOG-URL'
                if tag=='EVOLUTION-VIDEO-URL' :
                        tag='VIDEO-URL'
                if tag=='LABEL' :
                        tag='ADDRESS'
                
                
                cleaned_body+="\n"+tag+' : '+value;
                
        return cleaned_body;
        
       
          
            
        
##@author Alessio Di Pietro
#@author Irene Scionti
#@brief indicates the tags used for searching a memo or an event
class ics_tags(object):
    '''
    enum class for ics tags, it indicates the tags that can be used for searching an entry
    '''
    tags={};
    tags['summary']="SUMMARY";
    tags['description']="DESCRIPTION"
    tags['dtstart']="DTSTART"

##@author Alessio Di Pietro
#@author Irene Scionti
#@brief indicates the tags used for searching a contact
class vcard_tags(object):
    '''
    enum class for vcard tags, it indicates the tags that can be used for searching an entry
    
    '''
    tags={};
    tags['name']="FN";
